#include "internalgserver.h"

int GsvClientComp(void* _oldClient,void* _newClient)
{
    return  (((Client*)_oldClient)->m_fd < ((Client*)_newClient)->m_fd);
}

/*****************API FUNCTIONS***************************************************************/

/*Initillizing of struct passed to function*/
GenSv*  GsvServerNew(int _portTCP,int _portUDP,void* _appdata,int _headersize,
        HeaderFunc _headerFunc,
        NewClientCb _newClient,NewMesssageCb _newMessage,
        ClientDiscnCb _clientDiscn,
        size_t _exptMessagSize,NewExeptionCb _newExeption)
{
    GenSv*  sv;

    assert(_headersize);
    assert(_headerFunc);
    assert(_newClient);
    assert(_newMessage);
    assert(_clientDiscn);
    assert(_exptMessagSize);
    assert(_newExeption);

    sv = (GenSv*)malloc(sizeof(GenSv));
    if (sv == 0)
    {
        fprintf(stderr,"\nAllocation Server Failed line : %d \n",__LINE__);
        return 0;
    }

    sv->m_clientT =  BinTreeNew(GsvClientComp);
    if (sv->m_clientT == 0)
    {

        free(sv);
        fprintf(stderr,"\nAllocation Client Tree Failed line : %d \n",__LINE__);
        return 0;
    }

    /*UDP connection */
    sv-> m_clientTandUDP =  BinTreeNew(GsvClientComp);
    if (sv-> m_clientTandUDP == 0)
    {
        BinTreeDel(sv->m_clientT);
        free(sv);
        fprintf(stderr,"\nAllocation Client Tree Failed line : %d \n",__LINE__);
        return 0;
    }



    sv->m_portTCP      = _portTCP;
    sv->m_portUDP      = _portUDP;

    sv->m_appl      = _appdata;
    sv->m_headSize  = _headersize;
    sv->m_exmesSize = _exptMessagSize;
    sv->m_backlog   = BAKCLOG;
    sv->m_isStop    = 0;
    sv->m_Sched     = SchInit();
    if(sv->m_Sched == 0)
    {
        fprintf(stderr,"Scheduller allocation problems line : %d ", __LINE__);
        BinTreeDel (sv-> m_clientTandUDP);
        BinTreeDel(sv->m_clientT);
        free(sv);
        return 0;
    }

    sv->m_headF     = _headerFunc;
    sv->m_newClF    = _newClient;
    sv->m_newMesF   = _newMessage;
    sv->m_clDiscF   = _clientDiscn;
    sv->m_newExepF  = _newExeption;
    return sv;
}


int GsvServerRun(GenSv* _this)
{
    fd_set                  fd_rd;
    fd_set                  fd_wr;
    fd_set                  fd_ex;
    int                     maxfdsize;
    int                     numwaikedfd;
    struct timeval          wait;
    err_Gsv                 error = 0;

     /*set up the timout for select*//*STDIN_FIL*/

    _this->m_servSockfdTCP = GsvInit(_this->m_portTCP,TCP_PR);
/*    _this->m_servSockfdUDP = GsvInit(_this->m_portUDP,UDP_PR);*/

    /*Stars the select loop*/
    while(! (_this->m_isStop) )
    {
       GsvWaitTime(INOUT &wait,_this->m_Sched);
       maxfdsize = GsvBuildSelectList(_this,&fd_rd,&fd_wr,&fd_ex);
       numwaikedfd = select( maxfdsize,/*1st param - max number socket to check system define FD_SETSIZE ==1024*/
                            &(fd_rd),&(fd_wr),
                            &fd_ex,/*OUT_OF_BAND data transaction*/
                            &wait);/*waiting interwal :
                                   0 pointer- blocked indefinitely
                                    timeval == 0 - imidiatly (pooling)*/

        if ( numwaikedfd == -1)
        {
            perror("select");
            close(_this->m_servSockfdTCP);
            close(_this->m_servSockfdUDP);
            GsvServerDelete(_this);
            exit(EXIT_FAILURE);
        }

        if(FD_ISSET(STDIN_FILENO,&fd_rd))
        {
            break;
        }

        if ( numwaikedfd == 0)
        {
            if (! wait.tv_sec && ! wait.tv_usec)/*run task from server Task*/
            {
#ifdef _Unitest_Serv_Sched
                printf("\n!!!!!!!!!!!!!RUN SCHEDULLER!!!!!!!!!!!!!!\n");

#endif  /*_Unitest_Serv_Sched */
                SchRunOnce(_this->m_Sched);
/*                sleep(0);*/
            }
            else
            {
                /*nothing to use condition*/
                putchar('.');
                fflush(stdout);
            }
        }

        else
        {
           error = 0;
           GsvUseReadySocket(_this,&fd_rd,&fd_wr,&fd_ex,OUT &error);
           if ( error !=0)
           {
               fprintf(stderr,"\nRUN PROBLEMS SEE error log %d \n", error);
           }
        }
    }

    if (_this->m_isStop)
    {
        printf("\nServer work was stopped by application \n");
        fflush(stdout);
    }
    else
    {
        printf("\nServer work was stopped by input from STDIN \n");
        fflush(stdout);
    }

    close(_this->m_servSockfdTCP);
    close(_this->m_servSockfdUDP);
    return error;
}


void   GsvServerDrop(GenSv*  _this, int _idClient)
{
    BTreeIt   clientItr;
    Client*    client;
    Client     clientFind;

    assert(_this);
    assert(_idClient);
    clientFind.m_fd = _idClient;
    clientItr = BinTreeFind(_this->m_clientT,&clientFind);
    client = (BinTreeGetData(clientItr));
    client-> m_isdrop = DROP;
    return;
}

int    GsvServerWrite(GenSv* _this,int _idClient, void* _buf,size_t _bufsize)
{
    BTreeIt            clientItr;
    Client*             client;
    Client              temp;
    ListIter            messItr;
    IOblock*            message=0;
    assert(_this);

    assert(_buf);


    temp.m_fd = _idClient;
    clientItr = BinTreeFind(_this->m_clientT,&temp);

    if (clientItr == BinTreeEnd(_this->m_clientT))
    {
        fprintf(stderr,"\nClient with provided idClient : %d not found  \"GsvServerWrite\" line : %d\n",\
        _idClient, __LINE__);
        return 1;
    }

    client = (Client*)BinTreeGetData(clientItr);

    message = (IOblock*) calloc(1,sizeof(IOblock));
    if (message == 0)
    {
        perror("malloc");
        fprintf(stderr,"\nALLOCATION PROBLEMS  \"GsvServerWrite\" line : %d\n",__LINE__);
        GsvServerDrop( _this,_idClient);
        return 1;
    }

    if (GsvSetIO(message,_buf,_bufsize))/*copy message from aplicatiojn to server*/
    {
        GsvServerDrop( _this,_idClient);
        return 1;
    }
    client->m_isAlldone = NOT_DONE;
    messItr = ListEnd(client->m_messageQ);
    ListInsert(client->m_messageQ,messItr,message);
    return 0;
}


void   GsvServerStop(GenSv*  _this)
{
    assert(_this);
    _this->m_isStop = STOP;
}

void   GsvServerDelete(GenSv* _this)
{
    BTreeIt        clientItr;
    assert(_this);

    clientItr = BinTreeBegin(_this->m_clientT);
    while( !BinTreeIsEmpty(_this->m_clientT))
    {
        clientItr = GsvDropClients( _this->m_clientT,clientItr);
    }

    BinTreeDel(_this->m_clientT);
    SchDestroy(_this->m_Sched);
    free(_this);
    return;
}

void GsvSchedullerAddTask(GenSv* _this, Taskfunc _func,size_t _period,void* _data)
{
    SchInsertTask(_this->m_Sched,_func,_period,_data);
    return;
}

/*Implementation of Internal functions********************************************************/
static int GsvInit(int _port, int mode)
{
    int     servSockfd;

   if (mode == TCP_PR)
   {
       /*producing the server socket*/
       servSockfd = GsvSocketNewTCP(_port);
    /* close(servSockfd);*/
   }

    GsvSetSockNonBlock(servSockfd);
    /*Insert the the serverSocket in to listen state*/
    if (GsvListentoClient(servSockfd))
    {
        return -1;
    }
    return servSockfd;
}

static int GsvSocketNewTCP(int _port)
{
    int                     servSockfd;

    int      re_bind = 1;

    /*1.Obtain socket for listenign server socket*/
    servSockfd = socket( AF_INET /*1st argument is the purpose AF_UNIX local*/ ,
                SOCK_STREAM /*communication sematics SOCK_STREAM ==two way connect*/,
                IPPROTO_TCP/*Protocol TCP  0 use the default it is also TCP*/);

    if(servSockfd ==-1)
    {
        perror("socket");
        close(servSockfd);
        exit(EXIT_FAILURE);
        return 1;
    }

  /*2.Define of some socket options*/

    setsockopt(servSockfd,/*Will used for server*/
    SOL_SOCKET , /* Level of API for manipulation ( if we want to define somthing on TCP level the Protocol number will  be provided TCP*/
    SO_REUSEADDR,/* opt_name == SO_REUSEADDR this optins allows to to re-bind */
    (void*) &(re_bind),/*optval == 1 answer Yes or true for the opt_name (argument above)*/
     sizeof(re_bind)/*has to be sizeof(int) i don't undersand its usage*/
    );
    /*Binding*/
    GsvBind(servSockfd,_port);
    return servSockfd;
}



static void GsvBind(int _socket, int _port )
{
    struct sockaddr_in      serv_addr;

    /*Initiallizing of socket address struct*/
    memset((char *) &serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;/*Domain declaration , internet*/
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);/*converts number representation from  byte order to netorder*/
    serv_addr.sin_port =htons(_port);

    if( bind(_socket,(struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1 )
    {
        perror("bind");
        close(_socket);
        exit(EXIT_FAILURE);
    }
}

static void GsvSetSockNonBlock(int _socket)
{
    int     blkstat;
    /*to obtainet the current status*/
    blkstat = fcntl(_socket,F_GETFL);
    if (blkstat < 0)
    {
        perror("fcntl(F_GETFL)");
        close(_socket);
        return;
    }

    /*  SetSockNonBlock sets flag == O_NONBLOCK. this flag makes setting of socket to be
    non_blocking in all fucntions. In most of all
    funcitons instead of blocking routine : the errno will be set to EAGAIN.
     In "connect function" errno will obtains EINPROGRESS,
    the primary goal of this order to make the "accept" non blocking  */
    if ( fcntl(_socket,F_SETFL,blkstat| O_NONBLOCK) < 0)
    {
        perror("fcntl(F_SETFL)");
        close(_socket);
        return;
    }
    return;
}

static int  GsvListentoClient(int _socket)
{
    if( listen(_socket,BAKCLOG) )/*BACKLOG -is the lenght of clients queue on listening*/
    {
        perror("listen");
        return 1;
    }
    return 0;
}

static int GsvBuildSelectList(GenSv* _this, fd_set* _fd_rd,
                                fd_set* _fd_wr,fd_set* _fd_ex)
{
    BTreeIt        clientItr = BinTreeBegin(_this->m_clientT) ;
    BTreeIt        clientItrEnd = BinTreeEnd(_this->m_clientT);
    Client*         client;
    int             maxfd;

    FD_ZERO(_fd_rd);/*CLears or initialliziong of fd list*/
    FD_ZERO(_fd_wr);
    FD_ZERO(_fd_ex);
    FD_SET(_this->m_servSockfdTCP,_fd_rd);/*adds the _socket to the list of sockest for select, when the connection
                                to thes socket is arrived the select will not remove it from appropriate
                                fd_set.
                                By egreement the servSocket
                                will be with readed FD*/

     /*Insert fd of STDIN into fd_set*/
     FD_SET(STDIN_FILENO,_fd_rd);
    /*insert the file descriptors to fd_set*/
    while( !(BinTreeIsEqual(clientItr,clientItrEnd) == 1) )
    {
        client =(Client*)BinTreeGetData(clientItr);
        FD_SET(client->m_fd,_fd_rd);
        FD_SET(client->m_fd,_fd_ex);

        if ( !client->m_isAlldone ) /*At this wersion Alldone is flag that not all data writed*/
        {
            FD_SET(client->m_fd,_fd_wr);
        }

        clientItr =  BinTreeNext(clientItr);
    }

    /*Get the maximal filed descriptor the 1st argument of select function*/
    if ( BinTreeIsEmpty(_this->m_clientT) )
    {
        maxfd = _this->m_servSockfdTCP+1;
    }
    else
    {
       client = (Client*)BinTreeGetData (  BinTreePrev(clientItrEnd) );
       maxfd  =client->m_fd +1;
    }
    return maxfd;
}

static void GsvWaitTime(struct timeval* _wait, SchSched* _Sch)
{
    size_t   millisec;
    assert(_wait);
    assert(_Sch);

     millisec = SchGetTimeToNextTask(_Sch);
     _wait->tv_sec =  millisec/1000;
     _wait->tv_usec = millisec % 1000;
}


/*If o.k returns 0 else returns error log*/
static void GsvUseReadySocket(GenSv* _this,fd_set* _fd_rd, fd_set* _fd_wr,
                                fd_set* _fd_ex,OUT err_Gsv* _error)
{

    err_Gsv     err;
    BTreeIt    newClientIter ;
    Client*     tempClient = 0;
    BTreeIt    clientItr ;
    BTreeIt    clientItrEnd;


 /*Determind  is exist request for new connection*/
     if(FD_ISSET(_this->m_servSockfdTCP,_fd_rd))
     {
         if ( (err = GsvAcceptNewClient(_this,OUT &newClientIter)) )
         {
              *_error = err;
         }
     }

    clientItr    = BinTreeBegin(_this->m_clientT);
    clientItrEnd = BinTreeEnd(_this->m_clientT);
    /*This loop will check all active file descriptors
    and drop it to be need*/
    while( !BinTreeIsEmpty(_this->m_clientT) && !(BinTreeIsEqual(clientItr,clientItrEnd) == 1) )
    {
        tempClient = (Client*) BinTreeGetData(clientItr);
        /*write fd*/
        if( FD_ISSET(tempClient->m_fd,_fd_wr) )
        {
            /*After this functino the cliet -> m_isdorp flag and m_isAlldone can be changed*/
            if ( (err = GsvSend(_this,tempClient) ) )
            {
                *_error = err;
            }
        }

        /* read oob*/
        if( FD_ISSET(tempClient->m_fd,_fd_ex) )
        {
            /*If drop flag == yes nothing has to be read*/
            if (!tempClient->m_isdrop)
            {
                if ( (err = GsvRecvOOB(tempClient) ) )
                {
                    *_error = err;
                }
            }
        }
        /* read */
        if( FD_ISSET(tempClient->m_fd,_fd_rd) )
        {
            /*If drop flag == yes nothing has to be read*/
            if (!tempClient->m_isdrop)
            {
                if ( (err = GsvRecv(_this,tempClient) ) )
                {
                    *_error = err;
                }
            }
        }
        /*check is it could be droped at the end of loop*/
        if (tempClient->m_isAlldone && tempClient->m_isdrop )
        {
            /*My tree doednot work correctly .
            in deleting last element return its parent*  -- If right tree is used we don;t need this part
            if(BinTreeNext( clientItr) == BinTreeEnd(_this->m_clientT) )
            {
                clientItr = GsvDropClients(_this->m_clientT,clientItr);
                break;
            }*/
            clientItr = GsvDropClients(_this->m_clientT,clientItr);
        }
        else
        {
            clientItr =  BinTreeNext(clientItr);
        }
    }
return;
}

static err_Gsv GsvAcceptNewClient(GenSv* _this, OUT BTreeIt* _newClientIter)
{
    int         connectfd=0;
    Client*     newClient;

    connectfd = MakeNewConnection(_this->m_servSockfdTCP);
    if (connectfd == -1)
    {
        printf("\n Connection failed \n");
        return GSV_NEW_CLIENT_CONNECTION_PROBLEM;
    }
        /*      Create its struct*/

    if ( (newClient = GsvNewClient(connectfd,_this-> m_headSize)) == 0 )
    {
        fprintf(stderr,"\nNEW_CLIENT_CREATION_PROBLEMS\n");
        return GSV_NEW_CLIENT_CREATION_PROBLEMS;
    }
    /*Insert New Client to to tree
        Send the Callback*/
   *_newClientIter = GsvAddNewClientandCB(_this,newClient);
   if ( *_newClientIter == 0 )
   {
       /*GsvclientDestroy(newClient);
       newClient = DEADBEAF;*/
       GsvClientPrepare2Disconnect(_this,newClient);
       fprintf(stderr,"\nGSV_NEW_CLIENT_INSERTION_PROBLEMS\n");
       return GSV_NEW_CLIENT_INSERTION_PROBLEMS;
   }
   return 0;
}

static int MakeNewConnection(int _servSocket)
{
    /*fd only and returns it*/

    int                     statconnect = 0;
    int                     l;
    struct sockaddr_in      saddr;

    l= sizeof(saddr);/*This is INOUT PARAMETER used for verification is the right
                                        struct type is accepted*/
    statconnect = accept(_servSocket,(struct sockaddr*)&saddr, (socklen_t*)&l);
    if (statconnect == -1)
    {
        perror("accept");
        return -1;
    }
#ifdef _DEBUGSV
    fprintf(stdout,"connection esteblished from %s\n" , inet_ntoa(saddr.sin_addr));
#endif /*_DEBUGSV*/
    GsvSetSockNonBlock(statconnect);
    return statconnect;
}

static Client* GsvNewClient(int _newclientfd, int _buffersize)
{
    /*1. Create the client struct*/
    Client*    newclient = (Client*)malloc(sizeof(Client));
    if (newclient == 0)
    {
        fprintf(stderr,"\n malloc new client fails, line :%d \n",__LINE__);
        return 0;
    }
    newclient->m_headerbuffer =(char*) malloc(_buffersize);
    if (newclient->m_headerbuffer == 0)
    {
        free(newclient);
        newclient = 0;
        fprintf(stderr,"\n malloc new buffer line :%d \n",__LINE__);
        return 0;
    }
    *(newclient->m_headerbuffer) = 0;

    newclient->m_messageQ = ListNew();
    if (newclient->m_messageQ == 0)
    {
        free(newclient->m_headerbuffer);
        newclient->m_headerbuffer = 0;
        free(newclient);
        newclient = 0;
        fprintf(stderr,"\n malloc new client message Q fails, line :%d \n",__LINE__);
        return 0;
    }

    newclient->m_fd           = _newclientfd;
    newclient->m_isAlldone    = DONE;/*All done no any request to perform*/
    newclient->m_isdrop       = NOT_DROP;
    newclient->m_isheadrd     = HEADER_NOT_READEN;

    newclient->m_readIO       = NULLIO;
    newclient->m_oobIO        = NULLIO;

    return newclient;
}

static BTreeIt GsvAddNewClientandCB(GenSv*_this,Client* _newclient)
{
    BTreeIt   newClientItr;
    assert(_this);
    assert(_newclient);

#ifdef _DEBUGGSV
Client*     testclient;
#endif /*_DEBUGGSV*/

    newClientItr = BinTreeInsert(_this-> m_clientT,(void*)_newclient);

#ifdef _DEBUGGSV
 printf("New Client with ID %d\n",(Client*) BinTreeGetData(newClientItr )->m_fd);
#endif /*_DEBUGGSV*/
   if ( BinTreeIsEqual(newClientItr ,BinTreeEnd(_this->m_clientT) ) )
   {
       return 0;
   }
    _this->m_newClF(_newclient->m_fd,_this->m_appl);
    return newClientItr;
}

static void GsvclientDestroy(Client* _Client)
{
    ListIter            iter;
    IOblock*            mess;
    assert(_Client);
    if (_Client-> m_readIO.m_buf)
    {
        free(_Client-> m_readIO.m_buf);
        _Client-> m_readIO.m_buf = 0;
    }


    if (_Client-> m_oobIO.m_buf)
    {
        free(_Client-> m_oobIO.m_buf);
        _Client-> m_oobIO.m_buf = 0;
    }

    close(_Client->m_fd);
    iter = ListBegin(_Client-> m_messageQ);
    while( iter!= ListEnd(_Client-> m_messageQ) )
    {
        mess = ListGetData(iter);
        if (mess->m_buf)
        {
            free(mess->m_buf);/*All data readed*/
        }
        mess->m_buf =0;
        if (mess)
        {
            free(mess);
        }

        iter =  ListErase(iter);
    }

    ListDel(_Client->m_messageQ);
    _Client->m_messageQ = 0;
    free(_Client->m_headerbuffer);
    _Client->m_headerbuffer = 0;
    free(_Client);
    return;
}

static int GsvSend(GenSv* _this,Client* _client)
{
    int         wr;
    ListIter   countIter;
    IOblock*   message;

    assert(_client);

    while(! ListIsEmpty(_client-> m_messageQ))
    {
         countIter = ListBegin(_client-> m_messageQ);
         message =  (IOblock*)ListGetData(countIter);

        /*send the buffer content*/
        wr = GsvIOandUpdate (_client->m_fd,message, WRITE);
        if (wr == -1)
        {
            fprintf(stderr,"\nSends message problems line: %d \n", __LINE__);
            GsvClientPrepare2Disconnect(_this,_client);
            return GSV_SYSTEM_SEND_MESSAGE_PROB;
        }

        if(wr == 0)
        {
            fprintf(stderr,"\nClient Disconnect on sending line: %d \n", __LINE__);
            GsvClientPrepare2Disconnect(_this,_client);
            break;
        }

        if(message->m_rest != 0) /* Not all data readed*/
        {
            return 0;
        }

        free(message->m_buf);/*All data readed*/
        message->m_buf = 0;
        free(message);
        message = 0;
         ListErase(countIter);
    }
      _client->m_isAlldone = DONE;
    return 0;
}

static int GsvSetIO(IOblock* _message,char* _buffer,size_t _size)
{
    assert(_message);
    assert(_buffer);

    _message-> m_donesize =0;
    _message-> m_rest = _size;
    _message->m_buf = (char*) malloc(_message-> m_rest);
    if(_message->m_buf == 0)
    {
        perror("malloc :");
        fprintf(stderr,"Allocation problesm malloc line %d",__LINE__);
        return 1;
    }
    memcpy(_message->m_buf, _buffer ,_size);
    return 0;
}

static int GsvRecvOOB(Client* _client)
{
    return 0;
}

/*Read messages from clients, when messsage arived initially allocate the buffer at size of header
after that reads the header and evaluate the total message size.
Reallocates the new buffer with appropriate size. At the end send the Message Callback to
application. If client disconnect chages all isAlldone flag in Client struct to 'DONE'
and send Disconnect CallBack to application.
returns error log*/
static int GsvRecv(GenSv* _this, Client* _client)
{
    int       leng;
    IOblock*  Rblock;

    assert(_this);
    assert(_client);

    Rblock = &_client->m_readIO;
      /*If new buffer arrived, it possible that also the header would be readed
       within some iterations*/
    if (! _client-> m_isheadrd )
    {
        Rblock->m_rest = _this->m_headSize - Rblock->m_donesize;

        leng = recv(_client->m_fd, _client->m_headerbuffer + Rblock -> m_donesize,
                Rblock->m_rest,MSG_DONTWAIT);
         Rblock -> m_donesize = leng;

        if (leng == -1)
        {
            fprintf(stderr,"\nRecieve header problems line: %d, file: %s \n", __LINE__, __FILE__);
            GsvClientPrepare2Disconnect(_this,_client);
            return GSV_SYSTEM_RECIEV_MESSAGE_PROB;
        }

        if (!leng ) /*Client dissconnect*/ /*Header can't be 0 !!!*/
        {
#ifdef _DEBUGSV
            fprintf(stderr,"\nClient Disconnect line: %d \n", __LINE__);
#endif /*_DEBUGSV*/
            GsvClientPrepare2Disconnect(_this,_client);
            return 0;
        }
          /*All  header buffer was readed*/
        if(leng == _this->m_headSize)
        {
            leng  = _this->m_headF(_client->m_headerbuffer,_client->m_fd,_this->m_appl);

            if (leng <= 0)
            {
                fprintf(stderr,"\nAcepted header not satisfy  to protocol: %d \n", __LINE__);
                GsvClientPrepare2Disconnect(_this,_client);
                return 0;
            }



            Rblock->m_buf = malloc (leng);
            if (Rblock->m_buf == 0)
            {
                fprintf(stderr,"\nAllocatoin problems line: %d \n", __LINE__);
                GsvClientPrepare2Disconnect(_this,_client);
                return 0;
            }

              Rblock->m_rest = leng;
              Rblock->m_donesize=0;
              _client-> m_isheadrd = READEN;
        }
    }
      /*The header already known*/
    if ( _client-> m_isheadrd )
    {
          leng = GsvIOandUpdate(_client->m_fd,Rblock,READ);

        if (leng == -1)
        {
            fprintf(stderr,"\nReciev message problems line: %d  file: %s \n", __LINE__,__FILE__);
            GsvClientPrepare2Disconnect(_this,_client);
            return GSV_SYSTEM_RECIEV_MESSAGE_PROB;
        }

        if (!leng ) /*Client dissconnect*/ /*Header can't be 0 !!!*/
        {
            GsvClientPrepare2Disconnect(_this,_client);
            return 0;
        }

        if ( Rblock->m_rest == 0 ) /*All message readed*/
        {
            _this->m_newMesF(_client->m_fd,_this->m_appl,Rblock->m_buf,
                                Rblock->m_donesize);
            GsvResetIO(Rblock);
            _client->m_isheadrd  = HEADER_NOT_READEN;
        }
    }
    return 0;
}

/*Mode 0 == READ Mode == 1 WRITE*/
static int GsvIOandUpdate(int _fd,IOblock* _ioblock,int _mode)
{
    int     leng;
    if (_mode == READ)
    {
        leng = recv(_fd, _ioblock->m_buf + _ioblock->m_donesize,
                _ioblock->m_rest,MSG_DONTWAIT);
    }

    if(_mode == WRITE)
    {
        leng = send(_fd, _ioblock->m_buf + _ioblock->m_donesize,
                _ioblock->m_rest,MSG_DONTWAIT);
    }
    _ioblock->m_donesize +=leng;
    _ioblock->m_rest -=leng;
return leng;
}

/*Chages flag and send Callback*/
static void GsvClientPrepare2Disconnect(GenSv* _this,Client* _client)
{
    _client->m_isAlldone = DONE;
   _this->m_clDiscF( _client->m_fd, _this->m_appl,
                        _client->m_readIO.m_rest);
    _client-> m_isdrop = DROP;
    return;
}

static void GsvResetIO(IOblock* _ioblock)
{
    assert(_ioblock);
    assert(_ioblock);

    free(_ioblock->m_buf);
    _ioblock->m_buf = 0;
    *_ioblock = NULLIO;
}

static BTreeIt GsvDropClients(BinTree* _tree,BTreeIt _dropClientItr)
{
    assert(_tree);
    assert(_dropClientItr);

#ifdef _DEBUGSV
    if ( _dropClientItr == BinTreeEnd(_tree) )
    {
        fprintf(stderr,"\nIlligal End Iterator accepted, line %d \n", __LINE__);
    }

    if ( BinTreeIsEmpty(_tree) )
    {
        fprintf(stderr,"\nIlligal Empty Tree accepted, line %d \n", __LINE__);
    }
#endif /*_DEBUGSV*/

    GsvclientDestroy( BinTreeGetData(_dropClientItr) );
    return BinTreeRemove(_tree,_dropClientItr);
}










